package com.tarena.demo.luban.all.main.consumer;

import com.tarena.demo.luban.all.main.service.OrderService;
import com.tarena.demo.luban.commons.exception.BusinessDemoException;
import com.tarena.demo.luban.protocol.order.param.OrderAddParam;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.TimeUnit;

@Component
@RocketMQMessageListener(
    topic="order-test-topic",
    consumerGroup="o-c-g1")
public class OrderAddConsumer implements RocketMQListener<OrderAddParam> {
    @Autowired
    private OrderService orderService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Override public void onMessage(OrderAddParam message) {
        //1. 根据消息数据 设置一个争抢的所有,保证同一个消息对应一把锁
        String lockKey="order:add:"+message.getOrderSn()+".lock";
        //2. 生成一个随机value值 调用redis客户端执行setnx+expire
        String value=new Random().nextInt(9000)+1000+"";
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        boolean tryLock=opsForValue.setIfAbsent(lockKey,value,10, TimeUnit.SECONDS);
        try{
            // 判断 while这样写 不适合高并发的多线程 比如秒杀10000个人抢一个库存
            while(!tryLock){
                //没抢到 等待5秒钟再次抢锁
                Thread.sleep(5000);
                tryLock=opsForValue.setIfAbsent(lockKey,value,10, TimeUnit.SECONDS);
            }
            //3 执行业务
            orderService.addOrder(message);
        }catch(BusinessDemoException e){
            e.printStackTrace();
        }catch(InterruptedException e){
            e.printStackTrace();
        }finally{
            //4 释放锁 先读取锁的value值 比对是否和随机数一致 一致才del释放
            String lockValue = opsForValue.get(lockKey);
            if (value.equals(lockValue)) {
                redisTemplate.delete(lockKey);
            }
        }
    }
}
